﻿using NUnit.Framework;
using AdventureWorks.DataAccess.Repositories;
using NHibernate;
using System;
using Moq;
namespace AdventureWorks.DataAccess.Test.repository.BaseClasses
{
    [TestFixture]
    public class TransactBaseTest
    {
        private TestTransactionBase _testCase;
        private Mock<ISessionFactory> _factory;
        private Mock<ISession> _session;
        private Mock<ITransaction> _transaction;
        protected int CheckValue;
        protected const int COMPARE_VALUE = 1;
        private Action _testAction;

        [SetUp]
        public void Setup()
        {
            _factory = new Mock<ISessionFactory>();
            _session = new Mock<ISession>();
            _factory.Setup(x => x.GetCurrentSession()).Returns(_session.Object);
            _transaction = new Mock<ITransaction>();
            _session.SetupGet(x => x.Transaction).Returns(_transaction.Object);
            _session.Setup(x => x.BeginTransaction()).Returns(_transaction.Object);
            _testCase = new TestTransactionBase(_session.Object);
            CheckValue = 0;
            _testAction = () => { CheckValue = COMPARE_VALUE; };
        }

        [Test]
        public void When_Call_Function_Should_Get_Transaction()
        {
            _testCase.CallTransactWithAction(_testAction);
            _session.VerifyGet(x => x.Transaction);
        }

        [Test]
        public void When_Transaction_Not_Active_Should_Being_One()
        {
            _transaction.SetupGet(x => x.IsActive).Returns(false);
            _testCase.CallTransactWithAction(_testAction);
            _session.Verify(x => x.BeginTransaction());
        }

        [Test]
        public void When_Transaction_Active_Should_Not_Create_New_One()
        {
            _transaction.SetupGet(x => x.IsActive).Returns(true);
            _session.Setup(x => x.BeginTransaction()).Throws(new Exception("Should not call begin transaction"));
            _testCase.CallTransactWithAction(_testAction);
        }

        [Test]
        public void When_Begin_Transaction_Should_Commit()
        {
            _transaction.SetupGet(x => x.IsActive).Returns(false);
            _testCase.CallTransactWithAction(_testAction);
            _transaction.Verify(x => x.Commit());
        }

        [TearDown]
        public void CheckActionBeingCalled()
        {
            Assert.AreEqual(COMPARE_VALUE, CheckValue);
        }

        private class TestTransactionBase : TransactionBase
        {
            public TestTransactionBase(ISession factory) : base(factory) { }

            public void CallTransactWithFunction<TResult>(Func<TResult> func)
            {
                Transact(func);
            }

            public void CallTransactWithAction(Action action)
            {
                Transact(action);
            }
        }
    }
}
